package com.gengzp.rpc.tools;

import com.fasterxml.jackson.core.type.TypeReference;
import com.gengzp.rpc.exception.RpcException;
import jakarta.annotation.PostConstruct;
import org.springframework.stereotype.Component;

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @ClassName RpcHttpRequester
 * @Description rpc框架Http请求器（使用Java自带HttpClient）
 * @Author gengzp
 * @Date 2025/8/20 20:55
 */
@Component
public class RpcHttpRequester {

    private final HttpClient httpClient;
    private static RpcHttpRequester rpcHttpRequester;

    // 注入Java HttpClient
    private RpcHttpRequester(HttpClient rpcHttpClient) {
        this.httpClient = rpcHttpClient;
    }

    @PostConstruct
    public void init() {
        rpcHttpRequester = this;
    }

    /**
     * 发送带有自定义请求头的post请求
     *
     * @param url         请求地址url
     * @param requestBody 请求参数
     * @param headers     请求头
     * @param typeRef     响应结果类型
     * @param <T>         响应结果类型
     * @return 响应结果
     */
    public static <T> T post(String url,
                             Object requestBody,
                             Map<String, String> headers,
                             TypeReference<T> typeRef) throws RpcException {
        try {
            // 1.构建请求体JSON
            String jsonBody = RpcJsonConvertor.convertObjectToJson(requestBody);

            // 2.构建请求
            HttpRequest.Builder requestBuilder = HttpRequest.newBuilder()
                    .uri(URI.create(url))
                    .timeout(Duration.ofSeconds(RpcEnvironmentVariableReader.getRpcTimeout()))
                    .header("Content-Type", "application/json")
                    .POST(HttpRequest.BodyPublishers.ofString(jsonBody, StandardCharsets.UTF_8));

            // 3.组装请求头
            if (headers != null && !headers.isEmpty()) {
                headers.forEach(requestBuilder::header);
            }

            // 4.发送post请求获取返回结果
            HttpResponse<String> response = rpcHttpRequester.httpClient
                    .send(requestBuilder.build(), HttpResponse.BodyHandlers.ofString());

            if (response.statusCode() < 200 || response.statusCode() >= 300) {
                throw RpcException.get(String.format("HTTP请求失败: 状态码 = {%d}", response.statusCode()));
            }

            // 5.将返回结果转换为目标类型
            return RpcJsonConvertor.convertJsonToGenericObject(response.body(), typeRef);
        } catch (Exception e) {
            throw RpcException.get(e.getMessage());
        }
    }

    /**
     * 发送带有自定义请求头和查询参数的get请求
     *
     * @param url     请求地址url
     * @param params  查询参数
     * @param headers 请求头
     * @param typeRef 响应结果类型
     * @param <T>     响应结果类型
     * @return 响应结果
     */
    public static <T> T get(String url,
                            Map<String, Object> params,
                            Map<String, String> headers,
                            TypeReference<T> typeRef) throws RpcException {
        try {
            // 1.构建带查询参数的URI
            String fullUrl = buildUrlWithParams(url, params);

            // 2.构建请求
            HttpRequest.Builder requestBuilder = HttpRequest.newBuilder()
                    .uri(URI.create(fullUrl))
                    .timeout(Duration.ofSeconds(RpcEnvironmentVariableReader.getRpcTimeout()))
                    .GET();

            // 3.组装请求头
            if (headers != null && !headers.isEmpty()) {
                headers.forEach(requestBuilder::header);
            }

            // 4.发送get请求获取返回结果
            HttpResponse<String> response = rpcHttpRequester.httpClient
                    .send(requestBuilder.build(), HttpResponse.BodyHandlers.ofString());

            if (response.statusCode() < 200 || response.statusCode() >= 300) {
                throw RpcException.get(String.format("HTTP请求失败: 状态码 = {%d}", response.statusCode()));
            }

            // 5. 将返回结果转换为目标类型
            return RpcJsonConvertor.convertJsonToGenericObject(response.body(), typeRef);
        } catch (Exception e) {
            throw RpcException.get(e.getMessage());
        }
    }

    /**
     * 发送带有自定义请求头和查询参数的get请求, 获取字符串结果
     *
     * @param url     请求地址url
     * @param params  查询参数
     * @param headers 请求头
     * @return 响应结果
     */
    public static String get(String url,
                             Map<String, Object> params,
                             Map<String, String> headers) throws RpcException {
        try {
            // 1.构建带查询参数的URI
            String fullUrl = buildUrlWithParams(url, params);

            // 2.构建请求
            HttpRequest.Builder requestBuilder = HttpRequest.newBuilder()
                    .uri(URI.create(fullUrl))
                    .timeout(Duration.ofSeconds(RpcEnvironmentVariableReader.getRpcTimeout()))
                    .GET();

            // 3.组装请求头
            if (headers != null && !headers.isEmpty()) {
                headers.forEach(requestBuilder::header);
            }

            // 4.发送get请求获取返回结果
            HttpResponse<String> response = rpcHttpRequester.httpClient
                    .send(requestBuilder.build(), HttpResponse.BodyHandlers.ofString());

            if (response.statusCode() < 200 || response.statusCode() >= 300) {
                throw RpcException.get(String.format("HTTP请求失败: 状态码 = {%d}", response.statusCode()));
            }

            // 5. 将返回结果转换为目标类型
            return response.body();
        } catch (Exception e) {
            throw RpcException.get(e.getMessage());
        }
    }

    /**
     * 构建带查询参数的URL
     */
    private static String buildUrlWithParams(String url, Map<String, Object> params) {
        if (params == null || params.isEmpty()) {
            return url;
        }

        String query = params.entrySet().stream()
                .map(entry -> entry.getKey() + "=" + entry.getValue())
                .collect(Collectors.joining("&"));

        return url + (url.contains("?") ? "&" : "?") + query;
    }

}
